home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Power 1997 December
/
MACPOWER-1997-12.ISO.7z
/
MACPOWER-1997-12.ISO
/
AMUG
/
PROGRAMMING
/
Raven 1.2 Examples.sit
/
Raven 1.2 Examples
/
BoxPaint
/
Source
/
Pane.cpp
< prev
next >
Wrap
Text File
|
1997-09-04
|
19KB
|
753 lines
/*
* File: Pane.h
* Summary: A pane displaying the 3D object and a 3D cursor.
* Written by: Jesse Jones
*
* Copyright ゥ 1997 Jesse Jones.
* For conditions of distribution and use, see copyright notice in ZTypes.h
*
* Change History (most recent first):
*
* <2> 5/02/97 JDJ OnTrackStop now only has a stopPt argument.
* <1> 2/07/97 JDJ Created
*/
#include "Pane.h"
#include <QD3DAcceleration.h>
#include <QD3DMath.h>
#include <Z3DCameras.h>
#include <Z3DDrawContexts.h>
#include <Z3DGroups.h>
#include <Z3DLights.h>
#include <Z3DPicks.h>
#include <Z3DRenderingLoops.h>
#include <Z3DRenderers.h>
#include <Z3DTransforms.h>
#include <Z3DUtils.h>
#include <ZCursor.h>
#include <ZTracker.h>
#include <ZView.h>
#include <ZWindow.h>
#include "Doc.h"
//-----------------------------------
// Constants
//
const MenuCommand kSoftwareRendererCmd = "Software Renderer";
const MenuCommand kHardwareRendererCmd = "Hardware Renderer";
const MenuCommand kBestRendererCmd = "Best Renderer";
// ===================================================================================
// Internal Functions
// ===================================================================================
//---------------------------------------------------------------
//
// GetUpVector
//
// Returns a default vector that points as much toward the y axis
// as it can. Expects the vectors to be normalized. At this point,
// what to do if the forward vector lies on the y axis is a point
// of thought. Currently, it returns vector pointing down the -Z
// axis.
//
//---------------------------------------------------------------
static T3DVector GetUpVector(const T3DVector& forwardVector)
{
T3DVector upVector;
if (forwardVector.x == 0.0 && forwardVector.z == 0.0) {
upVector.x = 0.0;
upVector.y = 0.0;
upVector.z = -1.0;
} else {
T3DVector tempVector(0.0, 1.0, 0.0);
T3DVector orthogonalVector = CrossProduct(tempVector, forwardVector);
tempVector = CrossProduct(forwardVector, orthogonalVector);
upVector = Normalize(tempVector);
}
return upVector;
}
#pragma mark -
// ===================================================================================
// class C3DBusyCursorIdler
// ===================================================================================
class C3DBusyCursorIdler : public T3DViewIdler {
typedef T3DViewIdler Inherited;
//-----------------------------------
// Initialization/Destruction
//
public:
virtual ~C3DBusyCursorIdler();
C3DBusyCursorIdler();
//-----------------------------------
// Inherited API
//
protected:
virtual bool OnIdle();
};
//---------------------------------------------------------------
//
// C3DBusyCursorIdler::~C3DBusyCursorIdler
//
//---------------------------------------------------------------
C3DBusyCursorIdler::~C3DBusyCursorIdler()
{
}
//---------------------------------------------------------------
//
// C3DBusyCursorIdler::C3DBusyCursorIdler
//
//---------------------------------------------------------------
C3DBusyCursorIdler::C3DBusyCursorIdler()
{
}
//---------------------------------------------------------------
//
// C3DBusyCursorIdler::OnIdle
//
//---------------------------------------------------------------
bool C3DBusyCursorIdler::OnIdle()
{
UCursorUtils::ForceBusy();
return true; // keep on truckin
}
#pragma mark -
// ===================================================================================
// class CRotateTracker
// ===================================================================================
class CRotateTracker : public TTracker {
typedef TTracker Inherited;
//-----------------------------------
// Initialization/Destruction
//
public:
virtual ~CRotateTracker();
CRotateTracker(TPane* pane, CDocument* doc, const TPoint& startPt);
//-----------------------------------
// Inherited API
//
protected:
virtual void OnTrackStart(const TPoint& startPt);
virtual TTracker* OnTrackContinue(const TPoint& anchorPt, const TPoint& prevPt, const TPoint& nextPt, bool mouseMoved);
virtual void OnTrackStop(const TPoint& stopPt);
//-----------------------------------
// Member Data
//
protected:
CDocument* mDoc;
};
//---------------------------------------------------------------
//
// CRotateTracker::~CRotateTracker
//
//---------------------------------------------------------------
CRotateTracker::~CRotateTracker()
{
}
//---------------------------------------------------------------
//
// CRotateTracker::CRotateTracker
//
//---------------------------------------------------------------
CRotateTracker::CRotateTracker(TPane* pane, CDocument* doc, const TPoint& startPt) : TTracker(pane, startPt, kDontTrackNonMovement)
{
ASSERT(doc != nil);
mDoc = doc;
}
//---------------------------------------------------------------
//
// CRotateTracker::OnTrackStart
//
//---------------------------------------------------------------
void CRotateTracker::OnTrackStart(const TPoint& startPt)
{
#pragma unused(startPt)
HideCursor();
}
//---------------------------------------------------------------
//
// CRotateTracker::OnTrackContinue
//
//---------------------------------------------------------------
TTracker* CRotateTracker::OnTrackContinue(const TPoint& anchorPt, const TPoint& prevPt, const TPoint& nextPt, bool mouseMoved)
{
#pragma unused(anchorPt, mouseMoved)
float dx = prevPt.v - nextPt.v;
float dy = nextPt.h - prevPt.h;
float xRot = dx*kQ3Pi/mPane->GetWidth();
float yRot = dy*kQ3Pi/mPane->GetHeight();
if (xRot != 0.0 || yRot != 0.0) {
T3DMatrix tempMatrix;
tempMatrix.SetRotateXYZ(xRot, yRot, 0.0);
mDoc->TransformModel(tempMatrix);
mPane->HandleUpdate();
}
return this;
}
//---------------------------------------------------------------
//
// CRotateTracker::OnTrackStop
//
//---------------------------------------------------------------
void CRotateTracker::OnTrackStop(const TPoint& stopPt)
{
#pragma unused(stopPt)
ShowCursor();
}
#pragma mark -
// ===================================================================================
// class CDrawTracker
// ===================================================================================
class CDrawTracker : public TTracker {
typedef TTracker Inherited;
//-----------------------------------
// Initialization/Destruction
//
public:
virtual ~CDrawTracker();
CDrawTracker(TPane* pane, CDocument* doc, const TPoint& startPt);
//-----------------------------------
// Inherited API
//
protected:
virtual void OnTrackStart(const TPoint& startPt);
virtual TTracker* OnTrackContinue(const TPoint& anchorPt, const TPoint& prevPt, const TPoint& nextPt, bool mouseMoved);
virtual void OnTrackStop(const TPoint& stopPt);
//-----------------------------------
// Member Data
//
protected:
CDocument* mDoc;
T3DWindowPointPick* mPickObject;
TQ3PickDetail mMask;
TQ3Param2D mFrom;
CPencil& mCursor;
T3DView& mView;
CTextureMap& mTexture;
bool mFirstTime;
T3DObjectPtr mLastHitObject;
};
//---------------------------------------------------------------
//
// CDrawTracker::~CDrawTracker
//
//---------------------------------------------------------------
CDrawTracker::~CDrawTracker()
{
delete mPickObject;
}
//---------------------------------------------------------------
//
// CDrawTracker::CDrawTracker
//
//---------------------------------------------------------------
CDrawTracker::CDrawTracker(TPane* pane, CDocument* doc, const TPoint& startPt) : TTracker(pane, startPt, kDontTrackNonMovement), mView(dynamic_cast<CPane*>(pane)->GetView()), mCursor(dynamic_cast<CPane*>(pane)->GetCursor()), mTexture(dynamic_cast<CPane*>(pane)->GetDoc()->GetTexture())
{
ASSERT(doc != nil);
mDoc = doc;
mFrom.u = -1.0;
mFrom.v = -1.0;
mMask = kQ3PickDetailMaskObject | kQ3PickDetailMaskPath | kQ3PickDetailMaskUV |
kQ3PickDetailMaskXYZ | kQ3PickDetailMaskNormal;
mPickObject = new T3DWindowPointPick(mMask);
}
//---------------------------------------------------------------
//
// CDrawTracker::OnTrackStart
//
//---------------------------------------------------------------
void CDrawTracker::OnTrackStart(const TPoint& startPt)
{
#pragma unused(startPt)
HideCursor();
mCursor.Show();
mFirstTime = true;
}
//---------------------------------------------------------------
//
// CDrawTracker::OnTrackContinue
//
// This code seems to screw up occasionally (especially near the
// poles). Note that the original SDK app misbehaved in the same
// way...
//
//---------------------------------------------------------------
TTracker* CDrawTracker::OnTrackContinue(const TPoint& anchorPt, const TPoint& prevPt, const TPoint& nextPt, bool mouseMoved)
{
#pragma unused(anchorPt, prevPt, mouseMoved)
const float kCursorSize = 0.25; // the size in relation to the model being
// Adjust the pick point
mPickObject->SetPoint(T2DPoint(nextPt));
ulong numHits = dynamic_cast<CPane*>(mPane)->HandlePick(mPickObject);
if (numHits > 0 && mPickObject->HasDetail(0, mMask)) {
T3DPickEntry entry = mPickObject->GetEntry(0);
// Move the 3D cursor to the new position.
S3DCursorLocation cursorPlacement;
cursorPlacement.location = entry.GetXYZPoint();
cursorPlacement.toward = -entry.GetNormal(); // Point it into the picked model for our cursor
cursorPlacement.up = GetUpVector(cursorPlacement.toward); // Since we don't have an up vector, get a default one
mCursor.MoveTo(cursorPlacement);
// We don't want to do this everytime
T3DObjectPtr object = entry.GetObject();
if (object != mLastHitObject) {
mLastHitObject = object; // Reset it for next time
// Adjust the cursor to match the object's group.
T3DHitPath hitPath = entry.GetHitPath();
T3DGroupPtr leafGroup = hitPath.GetLeafGroup();
if (T3DDisplayGroup* leaf = dynamic_cast<T3DDisplayGroup*>(leafGroup.Get()))
mCursor.Scale(*leaf, mView, kCursorSize);
}
// Paint a line on the texture if the UV coordinate has changed.
TQ3Param2D to = entry.GetUV();
if (mFrom.u != to.u || mFrom.v != to.v) {
if (mFirstTime) {
mFrom = to; // need a valid from
mFirstTime = false;
}
mTexture.DrawLine(mFrom, to);
mDoc->SetDirty();
mPane->HandleUpdate();
}
mPickObject->EmptyHitList();
mFrom = to;
}
return this;
}
//---------------------------------------------------------------
//
// CDrawTracker::OnTrackStop
//
//---------------------------------------------------------------
void CDrawTracker::OnTrackStop(const TPoint& stopPt)
{
#pragma unused(stopPt)
mCursor.Hide();
ShowCursor();
mPane->Invalidate(); // need to erase cursor
}
#pragma mark -
// ===================================================================================
// class CPane
// ===================================================================================
static TReanimatorRegister<CPane> sMyPaneRegistrar;
//---------------------------------------------------------------
//
// CPane::~CPane
//
//---------------------------------------------------------------
CPane::~CPane()
{
}
//---------------------------------------------------------------
//
// CPane::CPane
//
//---------------------------------------------------------------
CPane::CPane(TView* superView) : TPane(superView), MCommander(nil)
{
mDoc = nil;
}
//---------------------------------------------------------------
//
// CPane::Create [static]
//
//---------------------------------------------------------------
MReanimatable* CPane::Create(MReanimatable* parent)
{
return new CPane(dynamic_cast<TView*>(parent));
}
#pragma mark ハ
//---------------------------------------------------------------
//
// CPane::OnReanimated
//
//---------------------------------------------------------------
void CPane::OnReanimated()
{
Inherited::OnReanimated();
TWindow* window = dynamic_cast<TWindow*>(this->GetTopView());
ASSERT(window != nil);
mDoc = dynamic_cast<CDocument*>(window->GetSuperCommander());
ASSERT(mDoc != nil);
this->CreateView();
}
//---------------------------------------------------------------
//
// CPane::OnDraw
//
//---------------------------------------------------------------
void CPane::OnDraw(TCanvas& canvas, const TRegion& dirtyRgn)
{
#pragma unused(dirtyRgn)
TUseCanvasPort usePort(canvas);
T3DRenderLoop loop(mView);
do {
this->SubmitScene();
} while (loop.Rendering());
}
//---------------------------------------------------------------
//
// CPane::HandlePick
//
//---------------------------------------------------------------
ulong CPane::HandlePick(T3DPick* pickObject)
{
ulong hits = 0;
T3DPickLoop loop(mView, pickObject);
do {
this->SubmitScene();
} while (loop.Rendering());
hits = pickObject->GetNumHits();
return hits;
}
//---------------------------------------------------------------
//
// CPane::OnMouseDown
//
//---------------------------------------------------------------
bool CPane::OnMouseDown(const TMouseEvent& event)
{
TTracker* tracker = nil;
if (event.WasOptionKeyDown()) {
tracker = new CRotateTracker(this, mDoc, event.GetPosition());
tracker->Post();
} else {
tracker = new CDrawTracker(this, mDoc, event.GetPosition());
tracker->Post();
}
return kHandled;
}
//---------------------------------------------------------------
//
// CPane::OnAdjustCursor
//
//---------------------------------------------------------------
bool CPane::OnAdjustCursor(const TEvent& event)
{
if (event.WasOptionKeyDown())
UCursorUtils::SetCursor(kOpenHandCursor);
else
UCursorUtils::SetCursor(kArrowCursor);
return kHandled;
}
//---------------------------------------------------------------
//
// CPane::OnKeyDown
//
//---------------------------------------------------------------
bool CPane::OnKeyDown(const TKeyEvent& event)
{
bool handled = true;
const float kRotateBy = 0.05; // rotate by 5%
float dx = 0.0;
float dy = 0.0;
char ch = event.GetChar();
switch (ch) {
case kLeftArrowChar:
dy = -kRotateBy;
break;
case kRightArrowChar:
dy = kRotateBy;
break;
case kUpArrowChar:
dx = -kRotateBy;
break;
case kDownArrowChar:
dx = kRotateBy;
break;
default:
handled = false;
}
if (dx != 0.0 || dy != 0.0) {
T3DMatrix tempMatrix;
tempMatrix.SetRotateXYZ(dx*kQ32Pi, dy*kQ32Pi, 0.0);
mDoc->TransformModel(tempMatrix);
this->HandleUpdate(); // for auto-repeat
}
return handled;
}
//---------------------------------------------------------------
//
// CPane::OnMenuCommand
//
//---------------------------------------------------------------
bool CPane::OnMenuCommand(const MenuCommand& command)
{
bool handled = false;
T3DRendererPtr rendererPtr = mView.GetRenderer();
if (T3DInteractiveRenderer* renderer = dynamic_cast<T3DInteractiveRenderer*>(rendererPtr.Get())) {
long engineID = renderer->GetEngineID();
handled = true;
if (command == kSoftwareRendererCmd && engineID != kQAEngine_AppleSW) {
renderer->SetEngineID(kQAEngine_AppleSW);
mView.SetRenderer(*renderer); // ・・・ハis this really neccesary?
} else if (command == kHardwareRendererCmd && engineID != kQAEngine_AppleHW) {
renderer->SetEngineID(kQAEngine_AppleHW);
mView.SetRenderer(*renderer);
} else if (command == kBestRendererCmd && engineID != kQAVendor_BestChoice) {
renderer->SetEngineID(kQAVendor_BestChoice);
mView.SetRenderer(*renderer);
} else
handled = false;
}
return handled;
}
//---------------------------------------------------------------
//
// CPane::OnCommandStatus
//
//---------------------------------------------------------------
bool CPane::OnCommandStatus(const MenuCommand& command, SCommandStatus& status)
{
bool handled = true;
long engineID = '????';
T3DRendererPtr rendererPtr = mView.GetRenderer();
if (T3DInteractiveRenderer* renderer = dynamic_cast<T3DInteractiveRenderer*>(rendererPtr.Get()))
engineID = renderer->GetEngineID();
if (command == kSoftwareRendererCmd) {
status.enabled = true;
status.mark = engineID == kQAEngine_AppleSW ? kCheckMarkChar : noMark;
} else if (command == kHardwareRendererCmd) {
status.enabled = true;
status.mark = engineID == kQAEngine_AppleHW ? kCheckMarkChar : noMark;
} else if (command == kBestRendererCmd) {
status.enabled = true;
status.mark = engineID == kQAVendor_BestChoice ? kCheckMarkChar : noMark;
} else
handled = false;
return handled;
}
#pragma mark ハ
//---------------------------------------------------------------
//
// CPane::CreateView
//
//---------------------------------------------------------------
void CPane::CreateView()
{
// Create and set draw context.
SMacDrawContextData drawContextData((CWindowPtr) this->GetGrafPort(), T3DColorARGB(0.0, 0.2, 1.0, 1.0));
mView.SetDrawContext(T3DMacDrawContext(drawContextData));
// Create and set renderer.
mView.SetRenderer(T3DInteractiveRenderer());
// Create and set camera.
TQ3ViewAngleAspectCameraData perspectiveData;
perspectiveData.cameraData.placement.cameraLocation = T3DPoint(0.0, 0.0, 3.0);
perspectiveData.cameraData.placement.pointOfInterest = T3DPoint(0.0, 0.0, 0.0);
perspectiveData.cameraData.placement.upVector = T3DVector(0.0, 1.0, 0.0);
perspectiveData.cameraData.range.hither = 0.00001;
perspectiveData.cameraData.range.yon = 10;
perspectiveData.cameraData.viewPort.origin.x = -1.0;
perspectiveData.cameraData.viewPort.origin.y = 1.0;
perspectiveData.cameraData.viewPort.width = 2.0;
perspectiveData.cameraData.viewPort.height = 2.0;
perspectiveData.fov = 1.0;
perspectiveData.aspectRatioXToY = (float) this->GetWidth()/this->GetHeight();
mView.SetCamera(T3DViewAngleAspectCamera(perspectiveData));
// Create and set lights.
T3DLightGroup lights;
lights.AddObject(T3DAmbientLight(kRGBWhite, 0.3));
lights.AddObject(T3DPointLight(kRGBWhite, 0.6, T3DPoint(-10.0, 0.0, 10.0)));
lights.AddObject(T3DDirectionalLight(kRGBWhite, 0.2, T3DVector(10.0, 0.0, 10.0)));
mView.SetLightGroup(lights);
// Install an idler so the cursor spins during long operations.
mView.SetIdleMethod(new C3DBusyCursorIdler);
}
//---------------------------------------------------------------
//
// CPane::SubmitScene
//
//---------------------------------------------------------------
void CPane::SubmitScene()
{
S3DScene scene = mDoc->GetScene();
// Styles
scene.interpolation->Submit(mView);
scene.backFacing->Submit(mView);
scene.fillStyle->Submit(mView);
{
// Save the current graphic state.
T3DPushState saveState(mView);
// Rotation
T3DMatrixTransform::Submit(scene.rotation, mView);
// Model
scene.model->Submit(mView);
}
// Cursor
mCursor.Submit(mView);
}